package com.example.demo.common.utils;

import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class TimeTransUtil {

    /**
     * get TIMESTAMP
     *
     * @return TIMESTAMP
     */
    public static long getUtcNowMileSeconds() {
        return OffsetDateTime.now(ZoneOffset.UTC).toInstant().toEpochMilli();
    }

    public static OffsetDateTime getLocalNow() {
        int offset = getOffset();
        return OffsetDateTime.now(ZoneOffset.ofHours(offset));
    }

    /**
     * get offsetDateTime with zone offset
     * 类似于C#的 DateTimeOffset类
     *
     * @param offset 时区
     * @return DateTime Now with local offset
     */
    public static OffsetDateTime getLocalNow(int offset) {
        return OffsetDateTime.now(ZoneOffset.ofHours(offset));
    }

    public static long getTimestamp(LocalDate localDate, int offset) {
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneOffset.ofHours(offset));
        return zonedDateTime.toInstant().toEpochMilli();
    }

    public static long getTimestamp(LocalDateTime localDateTime, int offset) {
        return localDateTime.toInstant(ZoneOffset.ofHours(offset)).toEpochMilli();
    }

    public static LocalDate getDate(long time, int offset, String pattern) {
        var dt = getOffsetDT(time, offset);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDate.parse(dt.format(formatter));
    }

    /**
     * OffsetDateTime 转时间戳
     *
     * @param dt OffsetDateTime
     * @return long
     */
    public static Long getTimestamp(OffsetDateTime dt) {
        if (dt == null)
            return null;
        return dt.toInstant().toEpochMilli();
    }

    /**
     * 时间戳離加一天
     *
     * @param mileSeconds 13位时间戳
     * @param offset      时区
     * @return long
     */
    public static long timestampAddOneDay(long mileSeconds, int offset) {
        return mileSeconds + 86400000L;
    }

    /**
     * 时间戳離加一年
     *
     * @param mileSeconds 13位时间戳
     * @param offset      时区
     * @return long
     */
    public static long timestampAddOneYear(long mileSeconds, int offset) {
        var eTime = getOffsetDT(mileSeconds, offset).plusYears(1);
        return getTimestamp(eTime);
    }

    /**
     * 时间戳離加一小时
     *
     * @param mileSeconds 13位时间戳
     * @param offset      时区
     * @return long
     */
    public static long timestampAddOneHour(long mileSeconds, int offset) {
        var eTime = getOffsetDT(mileSeconds, offset).plusHours(1);
        return getTimestamp(eTime);
    }

    /**
     * get offset DateTime
     *
     * @return OffsetDateTime
     */
    public static OffsetDateTime getOffsetDT(Long mileSeconds) {
        if (mileSeconds == null)
            return OffsetDateTime.now();

        // TODO 从浏览器获取
        String timezone = "Asia/Shanghai";
        return OffsetDateTime.ofInstant(Instant.ofEpochMilli(mileSeconds), ZoneId.of(timezone));
    }

    public static OffsetDateTime getOffsetDT(Long mileSeconds, int offset) {
        if (mileSeconds == null)
            return null;
        return OffsetDateTime.ofInstant(Instant.ofEpochMilli(mileSeconds), ZoneOffset.ofHours(offset));
    }

    /**
     * 根据时间戳转换成LocalDateTime
     *
     * @param time
     * @param toMile
     * @param offset
     * @return
     */
    public static LocalDateTime GetLocalDateTimeBy(long time, boolean toMile, int offset) {
        Instant is = null;
        if (toMile) {
            is = Instant.ofEpochMilli(time);
        } else {
            is = Instant.ofEpochSecond(time);
        }
        return LocalDateTime.ofInstant(is, ZoneOffset.ofHours(offset));
    }

    /**
     * 时间转换为10位时间戳
     *
     * @param time
     * @param offset
     * @return
     */
    public static long trans2EpochSecond(LocalDateTime time, int offset) {
        return time.toEpochSecond(ZoneOffset.ofHours(offset));
    }

    /**
     * 时间转换为13位时间戳
     *
     * @param time
     * @param offset
     * @return
     */
    public static long trans2EpochMili(LocalDateTime time, int offset) {
        return time.toInstant(ZoneOffset.ofHours(offset)).toEpochMilli();
    }

    /**
     * 获取格式化字符串
     *
     * @param time   时间戳
     * @param offset 时区
     * @return 返回  yyyy-MM-dd HH:mm 格式的时间
     */
    public static String formatterMinuteStr(long time, int offset) {
        var dt = getOffsetDT(time, offset);
        return dt.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
    }

    /**
     * 获取格式化字符串
     *
     * @param time   时间戳
     * @param offset 时区
     * @return 返回  yyyy-MM-dd 格式的时间
     */
    public static String formatterDayStr(long time, int offset) {
        var dt = getOffsetDT(time, offset);
        return dt.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
    }

    /**
     * 获取格式化字符串
     *
     * @param time   时间戳
     * @param offset 时区
     * @return 返回  yyyy-MM-dd HH:mm:ss 格式的时间
     */
    public static String formatterSecondStr(long time, int offset) {
        var dt = getOffsetDT(time, offset);
        return dt.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
    }

    /**
     * 获取格式化字符串
     *
     * @param time    OffsetDateTime
     * @param pattern "yyyy-MM-dd HH:mm:ss"
     * @return 返回  yyyy-MM-dd HH:mm 格式的时间
     */
    public static String formatterDateStr(OffsetDateTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取格式化字符串
     *
     * @param time
     * @param pattern "yyyy-MM-dd HH:mm:ss"
     * @return
     */
    public static String formatterDateStr(LocalDateTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String formatterDateStr(long st, int offset, String pattern) {
        var time = getOffsetDT(st, offset);
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static int getTimeOffset(String timeZone) {
        ZoneId zoneId = ZoneId.of(timeZone);
        ZoneOffset zoneOffset = zoneId.getRules().getOffset(Instant.now());
        return zoneOffset.getTotalSeconds() / 3600;
    }

    /**
     * 取整到10分钟
     *
     * @param time 时间 例如 2023/3/2 16:57:34
     * @return 返回 2023/3/2 16:50:00
     */
    public static OffsetDateTime RoundToMinute(OffsetDateTime time) {
        var offsetStr = time.getOffset().toString();
        OffsetDateTime temp = OffsetDateTime.parse(time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:00" + offsetStr)));
        return temp.plusMinutes((time.getMinute() / 10) * 10 + 10);
    }

    /**
     * 按每十分钟 向前取整
     *
     * @param timeStamp 时间戳
     * @param offset    时区
     * @return
     */
    public static Long floorMinute(Long timeStamp, int offset) {
        OffsetDateTime time = getOffsetDT(timeStamp, offset);
        int minute = time.getMinute();
        int second = time.getSecond();
        OffsetDateTime newTime = time.minusMinutes(minute % 10).minusSeconds(second);
        return getTimestamp(newTime);
    }

    /**
     * 按每十分钟向后取整
     *
     * @param timeStamp 时间戳
     * @param offset    时区
     * @return
     */
    public static Long ceilMinute(Long timeStamp, int offset) {
        OffsetDateTime time = getOffsetDT(timeStamp, offset);
        int minute = time.getMinute();
        int second = time.getSecond();
        if (minute % 10 == 0 && second == 0) {
            return timeStamp;
        } else {
            OffsetDateTime newTime = time.plusMinutes(10 - (minute % 10)).minusSeconds(second);
            return getTimestamp(newTime);
        }
    }

    /**
     * 获取两个日期相差多少个月
     *
     * @param date1
     * @param date2
     * @return int
     * @throws ParseException
     */
    public static int getMonthSpace(Date date1, Date date2)
            throws ParseException {
        int result = 0;
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(date1);
        c2.setTime(date2);
        int i = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
        int month = 0;
        if (i < 0) {
            month = -i * 12;
        } else if (i > 0) {
            month = i * 12;
        }
        result = (c2.get(Calendar.MONDAY) - c1.get(Calendar.MONTH)) + month;
        return result == 0 ? 1 : Math.abs(result);
    }

    /**
     * 获取 "HH:mm" 格式的毫秒
     *
     * @param time String
     * @return Long
     */
    public static Long getTimestamp(String time, int offset) {
        var dt = OffsetDateTime.parse(String.format("1970-01-02T%s+%02d:00", time, offset));
        return dt.toInstant().toEpochMilli() % 86400000;
    }

    /**
     * 修改时间的年份
     *
     * @param timestamp
     * @param year
     * @param offset
     * @return
     */
    public static Long changeYear(long timestamp, int year, int offset) {
        var dt = getOffsetDT(timestamp, offset);
        var tt = changeYear(dt, year);
        return getTimestamp(tt);
    }

    /**
     * 修改时间的年份
     *
     * @param dateTime OffsetDateTime
     * @param year     int
     * @return OffsetDateTime
     */
    public static OffsetDateTime changeYear(OffsetDateTime dateTime, int year) {
        YearMonth yearMonth = YearMonth.of(year, dateTime.getMonthValue());
        int dayOfMonth = Math.min(dateTime.getDayOfMonth(), yearMonth.lengthOfMonth());
        if (yearMonth.isValidDay(dayOfMonth)) {
            return dateTime.withYear(year).withDayOfMonth(dayOfMonth);
        } else {
            int lastDayOfMonth = yearMonth.lengthOfMonth();
            dayOfMonth = Math.min(dateTime.getDayOfMonth(), lastDayOfMonth);
            return dateTime.withYear(year).withMonth(dateTime.getMonthValue()).withDayOfMonth(dayOfMonth);
        }
    }

    public static int getOffset(String zoneId) {
        return getZoneOffset(zoneId).getTotalSeconds() / 3600;
    }

    public static ZoneOffset getZoneOffset(String zoneId) {
        var timezone = ZoneId.of(zoneId);
        return timezone.getRules().getOffset(LocalDateTime.now());
    }

    public static int getOffset() {
        return getOffset("Asia/Shanghai");
    }

    public static ZoneOffset getZoneOffset() {
        return getZoneOffset("Asia/Shanghai");
    }

    public static List<OffsetDateTime> getTimeIntervals(OffsetDateTime startTime, OffsetDateTime endTime, TemporalUnit unit, long amount) {
        List<OffsetDateTime> timeIntervals = new ArrayList<>();
        OffsetDateTime currentTime = startTime;
        while (currentTime.isBefore(endTime) || currentTime.equals(endTime)) {
            timeIntervals.add(currentTime);
            currentTime = currentTime.plus(amount, unit);
        }

        return timeIntervals;
    }

    /**
     * 去掉时间戳的时分秒毫秒部分
     *
     * @param timestamp
     * @param zoneOffset
     * @return
     */
    public static long stripTime(long timestamp, ZoneOffset zoneOffset) {
        return (timestamp + zoneOffset.getTotalSeconds() * 1000L) / (24 * 60 * 60 * 1000L) * (24 * 60 * 60 * 1000L) - zoneOffset.getTotalSeconds() * 1000L;
    }
}
